From 12af54e17ad695b2cc535cfa5b986217a89daf9c Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 14 Jul 2014 10:57:04 -0700 Subject: [PATCH] Allow configuratin ar/ld for rustc This adds a new .cargo/config option which allows configuring the ar and linker tools that rustc invokes. This should aid in any cross-compilation attempts. --- src/cargo/ops/cargo_compile.rs | 70 ++++++++++++++++++++++++------- src/cargo/ops/cargo_rustc/mod.rs | 19 ++++++--- src/cargo/util/config.rs | 39 +++++++++++++++++ tests/test_cargo_cross_compile.rs | 38 +++++++++++++++++ 4 files changed, 145 insertions(+), 21 deletions(-) diff --git a/src/cargo/ops/cargo_compile.rs b/src/cargo/ops/cargo_compile.rs index 44fba5c80..b4d91f1f9 100644 --- a/src/cargo/ops/cargo_compile.rs +++ b/src/cargo/ops/cargo_compile.rs @@ -23,12 +23,14 @@ //! use std::os; -use util::config::{Config, ConfigValue}; -use core::{MultiShell, Source, SourceId, PackageSet, Target, PackageId, resolver}; +use std::collections::HashMap; + use core::registry::PackageRegistry; +use core::{MultiShell, Source, SourceId, PackageSet, Target, PackageId, resolver}; use ops; use sources::{PathSource}; -use util::{CargoResult, Wrap, config, internal, human}; +use util::config::{Config, ConfigValue}; +use util::{CargoResult, Wrap, config, internal, human, ChainError}; pub struct CompileOptions<'a> { pub update: bool, @@ -57,7 +59,8 @@ pub fn compile(manifest_path: &Path, try!(shell.warn(format!("unused manifest key: {}", key))); } - let override_ids = try!(source_ids_from_config()); + let user_configs = try!(config::all_configs(os::getcwd())); + let override_ids = try!(source_ids_from_config(&user_configs)); let source_ids = package.get_source_ids(); let (packages, resolve) = { @@ -85,6 +88,7 @@ pub fn compile(manifest_path: &Path, }).collect::>(); let mut config = try!(Config::new(*shell, update, jobs, target)); + try!(scrape_target_config(&mut config, &user_configs)); try!(ops::compile_targets(env.as_slice(), targets.as_slice(), &package, &PackageSet::new(packages.as_slice()), &resolve, &mut config)); @@ -103,23 +107,57 @@ pub fn compile(manifest_path: &Path, Ok(test_executables) } -fn source_ids_from_config() -> CargoResult> { - let configs = try!(config::all_configs(os::getcwd())); - +fn source_ids_from_config(configs: &HashMap) + -> CargoResult> { debug!("loaded config; configs={}", configs); let config_paths = configs.find_equiv(&"paths").map(|v| v.clone()); let config_paths = config_paths.unwrap_or_else(|| ConfigValue::new()); - let paths: Vec = match *config_paths.get_value() { - config::String(_) => return Err(internal("The path was configured as \ - a String instead of a List")), - config::Table(_) => return Err(internal("The path was configured as \ - a Table instead of a List")), - config::List(ref list) => { - list.iter().map(|path| Path::new(path.as_slice())).collect() - } + let paths = try!(config_paths.list().chain_error(|| { + internal("invalid configuration for the key `path`") + })); + + Ok(paths.iter().map(|p| SourceId::for_path(&Path::new(p.as_slice()))).collect()) +} + +fn scrape_target_config(config: &mut Config, + configs: &HashMap) + -> CargoResult<()> { + let target = match configs.find_equiv(&"target") { + None => return Ok(()), + Some(target) => try!(target.table().chain_error(|| { + internal("invalid configuration for the key `target`") + })), + }; + let target = match config.target() { + None => target, + Some(triple) => match target.find_equiv(&triple) { + None => return Ok(()), + Some(target) => try!(target.table().chain_error(|| { + internal(format!("invalid configuration for the key \ + `target.{}`", triple)) + })), + }, }; - Ok(paths.iter().map(|p| SourceId::for_path(p)).collect()) + match target.find_equiv(&"ar") { + None => {} + Some(ar) => { + config.set_ar(try!(ar.string().chain_error(|| { + internal("invalid configuration for key `ar`") + })).to_string()); + } + } + + match target.find_equiv(&"linker") { + None => {} + Some(linker) => { + config.set_linker(try!(linker.string().chain_error(|| { + internal("invalid configuration for key `ar`") + })).to_string()); + } + } + + Ok(()) } diff --git a/src/cargo/ops/cargo_rustc/mod.rs b/src/cargo/ops/cargo_rustc/mod.rs index 300f66535..989889eac 100644 --- a/src/cargo/ops/cargo_rustc/mod.rs +++ b/src/cargo/ops/cargo_rustc/mod.rs @@ -278,12 +278,21 @@ fn build_base_args(into: &mut Args, into.push("--out-dir".to_string()); into.push(cx.dest(plugin).display().to_string()); - match cx.config.target() { - Some(target) if !plugin => { - into.push("--target".to_string()); - into.push(target.to_string()); + if !plugin { + fn opt(into: &mut Vec, key: &str, prefix: &str, + val: Option<&str>) { + match val { + Some(val) => { + into.push(key.to_string()); + into.push(format!("{}{}", prefix, val)); + } + None => {} + } } - _ => {} + + opt(into, "--target", "", cx.config.target()); + opt(into, "-C", "ar=", cx.config.ar()); + opt(into, "-C", "linker=", cx.config.linker()); } } diff --git a/src/cargo/util/config.rs b/src/cargo/util/config.rs index 7525e7787..a8e71d3e3 100644 --- a/src/cargo/util/config.rs +++ b/src/cargo/util/config.rs @@ -13,6 +13,8 @@ pub struct Config<'a> { shell: &'a mut MultiShell, jobs: uint, target: Option, + linker: Option, + ar: Option, } impl<'a> Config<'a> { @@ -32,6 +34,8 @@ impl<'a> Config<'a> { shell: shell, jobs: jobs.unwrap_or(os::num_cpus()), target: target, + ar: None, + linker: None, }) } @@ -58,6 +62,17 @@ impl<'a> Config<'a> { pub fn target<'a>(&'a self) -> Option<&'a str> { self.target.as_ref().map(|t| t.as_slice()) } + + pub fn set_ar(&mut self, ar: String) { self.ar = Some(ar); } + + pub fn set_linker(&mut self, linker: String) { self.linker = Some(linker); } + + pub fn linker<'a>(&'a self) -> Option<&'a str> { + self.linker.as_ref().map(|t| t.as_slice()) + } + pub fn ar<'a>(&'a self) -> Option<&'a str> { + self.ar.as_ref().map(|t| t.as_slice()) + } } #[deriving(Eq,PartialEq,Clone,Encodable,Decodable)] @@ -161,6 +176,30 @@ impl ConfigValue { Ok(()) } + + pub fn string<'a>(&'a self) -> CargoResult<&'a str> { + match self.value { + Table(_) => Err(internal("expected a string, but found a table")), + List(_) => Err(internal("expected a string, but found a list")), + String(ref s) => Ok(s.as_slice()), + } + } + + pub fn table<'a>(&'a self) -> CargoResult<&'a HashMap> { + match self.value { + String(_) => Err(internal("expected a table, but found a string")), + List(_) => Err(internal("expected a table, but found a list")), + Table(ref table) => Ok(table), + } + } + + pub fn list<'a>(&'a self) -> CargoResult<&'a [String]> { + match self.value { + String(_) => Err(internal("expected a list, but found a string")), + Table(_) => Err(internal("expected a list, but found a table")), + List(ref list) => Ok(list.as_slice()), + } + } } impl ConfigValueValue { diff --git a/tests/test_cargo_cross_compile.rs b/tests/test_cargo_cross_compile.rs index 9483e82d0..e049cfd14 100644 --- a/tests/test_cargo_cross_compile.rs +++ b/tests/test_cargo_cross_compile.rs @@ -4,8 +4,10 @@ #![cfg(target_os = "macos")] use std::os; +use std::path; use support::{project, execs, basic_bin_manifest}; +use support::{RUNNING, COMPILING}; use hamcrest::{assert_that, existing_file}; use cargo::util::process; @@ -230,3 +232,39 @@ test!(plugin_to_the_max { process(foo.target_bin(target, "main")), execs().with_status(0)); }) + +test!(linker_and_ar { + let target = alternate(); + let p = project("foo") + .file(".cargo/config", format!(r#" + [target.{}] + ar = "my-ar-tool" + linker = "my-linker-tool" + "#, target).as_slice()) + .file("Cargo.toml", basic_bin_manifest("foo").as_slice()) + .file("src/foo.rs", r#" + use std::os; + fn main() { + assert_eq!(os::consts::ARCH, "x86"); + } + "#); + + assert_that(p.cargo_process("cargo-build").arg("--target").arg(target) + .arg("-v"), + execs().with_status(101) + .with_stdout(format!("\ +{running} `rustc src/foo.rs --crate-name foo --crate-type bin \ + --out-dir {dir}{sep}target{sep}{target} \ + --target {target} \ + -C ar=my-ar-tool -C linker=my-linker-tool \ + -L {dir}{sep}target{sep}{target} \ + -L {dir}{sep}target{sep}{target}{sep}deps` +{compiling} foo v0.5.0 (file:{dir}) +", + running = RUNNING, + compiling = COMPILING, + dir = p.root().display(), + target = target, + sep = path::SEP, + ).as_slice())); +}) -- 2.30.2